/**
 * 所有动作共用方法
 */
function sActionShare(){
    /**
     * 深度克隆偏移量
     * @param {*} offset 
     * @returns 
     */
    this.deepCloneOffset = function(offset){
        if(!offset) return {};

        var result = {...offset};
        if(offset.range){
            result.range = {...offset.range};
        }
        
        if(offset.next){
            var next = offset.next;
            var rNext = result;
            while(next){
                rNext.next = {...next};
                if(next.range){
                    rNext.range = {...next.range};
                }
                rNext = rNext.next;
                next = next.next;
            }
        }

        return result;
    }

    /**
     * 抽取offset最深层的偏移量
     * @param {*} offset 
     */
    this.extractDeepOffset = function(offset){
        var result = {
            pageIndex: offset.pageIndex,
            rowIndex: offset.rowIndex,
            elementIndex: offset.elementIndex,
            contentIndex: offset.contentIndex
        };

        if(offset.start != null){
            result.start = offset.start;
        }

        if(offset.end != null){
            result.end = offset.end;
        }

        var next = offset.next;
        var prev = null;

        while(next){
            prev = next;
            next = next.next;
            if(!next){
                result = {
                    pageIndex: prev.pageIndex,
                    rowIndex: prev.rowIndex,
                    elementIndex: prev.elementIndex,
                    contentIndex: prev.contentIndex,
                    tableRowIndex: prev.tableRowIndex,
                    tableColIndex: prev.tableColIndex
                };

                if(prev.start != null){
                    result.start = prev.start;
                }

                if(prev.end != null){
                    result.end = prev.end;
                }
            }
        }

        return result;
    }

    /**
     * 将偏移量进行合并
     * @param {*} offset 被合并偏移量
     * @param {*} mOffset 合并偏移量
     */
    this.mergeOffsetNext = function(offset, mOffset){
        if(!offset.next) {
            for(var i in mOffset){
                offset[i] = mOffset[i];
            }
            return offset;
        }

        for(var n = offset; n != null; n = n.next){
            if(!n.next.next) {
                n.next = {...n.next, ...mOffset};
                break;
            };
        }

        return offset;
    }

    /**
     * 获取元素的起始页到终止页的范围
     * @param {*} element 
     * @returns 
     */
    this.getElementPageRange = function(element){
        var boundRect = element.__boundRect;
        var result = {
            startPageIndex: -1,
            startRowIndex: -1,
            endPageIndex: -1,
            endRowIndex: -1
        };

        for(var i in boundRect){
            result.startPageIndex = parseInt(i);
            for(var j in boundRect[i]){
                result.startRowIndex = parseInt(j);
                break;
            }
            break;
        }

        result.endPageIndex = boundRect.length - 1;

        boundRect = boundRect[boundRect.length - 1];
        result.endRowIndex = boundRect.length - 1;

        return result;
    }

    /**
     * 中间属性
     */
    var middleProperties = [
        "newContent",
        "oldContent",
        "newStyle",
        "oldStyle",
        "newParagraphIndex",
        "oldParagraphIndex",
    ];

    /**
     * 清除对象中间属性
     * @param {*} el 
     */
    this.clearMiddleProperties = function(el){
        for(var i in middleProperties){
            delete el[middleProperties[i]];
        }
    }

    /**
     * 偏移量是否在元素的偏移范围内
     * @param {*} offset 
     * @param {*} elRange 
     * @returns 
     */
    this.isOffsetInRange = function(offset, elRange){
        if(!offset.pageIndex) return false;
        
        var next = this.extractDeepOffset(offset);

        return next.pageIndex < elRange.pageIndex 
            || next.pageIndex > elRange.pageIndex
            || next.rowIndex < elRange.rowIndex 
            || next.rowIndex > elRange.rowIndex;
    }

    /**
     * 遍历并克隆对象
     * @param {*} obj 
     */
    this.cloneData = function(data){
        var result = Array.isArray(data) ? [] : {};
        var item = null;

        for(var i in data){
            item = i.indexOf("__") > -1 ? undefined : data[i];

            if(typeof(data[i]) == "object" && (data[i] != null && Object.keys(data[i]).length > 0)){
                if(item !== undefined){
                    result[i] = this.cloneData(item);
                }
            }else{
                if(item !== undefined){
                    result[i] = item;
                }
            }
        }

        return result;
    }

    /**
     * 分裂文本元素
     * @param {*} element 元素
     * @param {*} offsets 偏移量
     * @param {*} opt 可选项
     */
    this.splitText = function(element, offsets, opt){
        if(element.placeholder){
            return {
                leftText: "",
                inText: "",
                rightText: ""
            };
        }

        opt = opt ? opt : {};

        var begin = this.extractDeepOffset(offsets[0]);
        if(begin.start == null){
            begin.start = begin.contentIndex;
            begin.end = begin.contentIndex;         
        }

        var length = 0;
        var trimLeftText = "";

        //获取元素不在偏移量范围的文本(小于偏移量)
        for(var i in element.__texts){
            if(i > begin.pageIndex) break;
            
            for(var j in element.__texts[i]){
                if(i == begin.pageIndex && j > begin.rowIndex) break;

                if(i < begin.pageIndex){
                    trimLeftText += element.__texts[i][j];
                }else if(i == begin.pageIndex){
                    if(j < begin.rowIndex){
                        trimLeftText += element.__texts[i][j];
                    }else if(j == begin.rowIndex){
                        trimLeftText += element.__texts[i][j]
                            .substring(0, begin.start + 1);
                    }
                }
            }
        }

        length += trimLeftText.length;

        var offset = null;
        var inText = "";

        //获取偏移量范围内的文本
        for(var i = 0; i < offsets.length; i++){
            offset = this.extractDeepOffset(offsets[i]);
            if(offset.start == null){
                offset.start = offset.contentIndex;
                offset.end = offset.contentIndex;         
            }
            inText += element.__texts[offset.pageIndex][offset.rowIndex]
                .substring(offset.start + 1, offset.end + 1);
            length += offset.end - offset.start;
        }

        //获取不在偏移量范围内文本(大于偏移量)
        var trimRightText = element.innerText.substring(length);

        return {
            leftText: trimLeftText,
            inText: inText,
            rightText: trimRightText
        };
    }

    /**
     * 包装文本元素
     * @param {*} element
     * @param {*} offset
     * @param {*} text 
     * @param {*} style
     * @param {*} opt
     */
    this.wrapElement = function(element, offset, text, style, opt){
        opt = opt ? opt : {};

        let elOffset = this.deepCloneOffset(offset);
        
        let el = {
            offset: elOffset,
            element: element
        };

        if(text != null){
            el.oldContent = element.innerText;
            el.newContent = text;

            element.innerText = text;
        }

        if(style){
            el.oldStyle = element.style;
            el.newStyle = {...element.style, ...style};

            element.style = el.newStyle;
        }

        if(opt.mutateNew){
            el.mutateNew = opt.mutateNew;
        }else{
            el.mutate = true;
        }

        //该元素不用来定位
        if(opt.notLocate){
            el.notLocate = opt.notLocate;
        }

        return el;
    }

    /**
     * 将分裂文本分别组合成元素返回
     * @param {*} splitText 分裂文本
     * @param {*} element 元素
     * @param {*} offset 偏移量
     * @param {*} wrapFunc 包装元素的方法
     * @param {*} opt 可选项
     */
    this.composeElements = function(splitText, element, offset, wrapFunc, opt){
        opt = opt ? opt : {};

        var result = {
            leftElement: null,
            inElement: null,
            rightElement: null
        };

        var style = { ...element.style };
        var next = this.extractDeepOffset(offset);
        var elementCount = next.elementIndex + 1;

        if(opt.lastElementIndex){
            if(opt.lastPageIndex == next.pageIndex && opt.lastRowIndex == next.rowIndex){
                elementCount = opt.lastElementIndex + 1;
            }else{
                opt.lastPageIndex = null;
                opt.lastRowIndex = null;
                opt.lastElementIndex = null;
            }
        }

        var leftTextCreate = splitText.leftText || (!splitText.leftText && opt.leftTextEmptyCreate);
        var inTextCreate = splitText.inText || (!splitText.inText && opt.inTextEmptyCreate);
        var rightTextCreate = splitText.rightText || (!splitText.rightText && opt.rightTextEmptyCreate);

        if(leftTextCreate){
            result.leftElement = wrapFunc.call(this, element, offset, splitText.leftText, null, opt);
            if(opt.lastElementIndex){
                this.mergeOffsetNext(result.leftElement.offset, {
                    elementIndex: elementCount++
                });
            }

            if(inTextCreate){
                opt.elementIndex = elementCount++;
                result.inElement = composeNewElement.call(
                    this, element, offset, splitText.inText, null, wrapFunc, opt);
            }

            if(splitText.newInText){
                opt.elementIndex = elementCount++;
                result.newInElement = composeNewElement.call(
                    this, element, offset, splitText.newInText, null, wrapFunc, opt);
            }

            if(rightTextCreate){
                result.rightElement = composeNewElement.call(
                    this, element, offset, splitText.rightText, style, wrapFunc, {
                        elementIndex: elementCount++
                    });
            }
        }else{
            if(inTextCreate){
                result.inElement = wrapFunc.call(this, element, offset, splitText.inText, opt.mutateStyle, opt);
                if(opt.lastElementIndex){
                    this.mergeOffsetNext(result.inElement.offset, {
                        elementIndex: elementCount++
                    });
                }

                if(splitText.newInText){
                    opt.elementIndex = elementCount++;
                    result.newInElement = composeNewElement.call(
                        this, element, offset, splitText.newInText, null, wrapFunc, opt);
                }

                if(rightTextCreate){
                    result.rightElement = composeNewElement.call(
                        this, element, offset, splitText.rightText, style, wrapFunc, {
                            elementIndex: elementCount++
                        });
                }
            }
        }

        opt.lastPageIndex = next.pageIndex;
        opt.lastRowIndex = next.rowIndex;
        opt.lastElementIndex = elementCount - 1;

        return result;
    }

    /**
     * 组合新元素
     * @param {*} element
     * @param {*} offset
     * @param {*} text 
     * @param {*} style 
     * @param {*} wrapFunc 
     * @param {*} opt 
     * @returns 
     */
    var composeNewElement = function(element, offset, text, style, wrapFunc, opt){
        var elem = this.cloneData(element);
        delete elem.placeholder;
        delete elem.placeholderColor;
        
        elem.__paragraphIndex = element.__paragraphIndex;
        elem.innerText = text;

        if(style){
            elem.style = {...style};
        }

        let elOffset = this.deepCloneOffset(offset);
        elOffset.range = {start: 0, end: text.length};

        this.mergeOffsetNext(elOffset, {elementIndex: opt.elementIndex});

        return wrapFunc.call(this, elem, elOffset, null, opt.mutateStyle, {
            mutateNew: true
        });
    }

    /**
     * 改变批注归属
     * @param {*} element 原始归属元素 
     * @param {*} toElement 新归属元素
     */
    this.changeAnnotation = function(element, toElement){
        if(!element || !element.annotation) return;

        toElement.annotation = element.annotation;
        toElement.annotationChildren = element.annotationChildren;
        
        element.annotationChildren = null;
    }

    /**
     * 链接两个元素
     * @param {*} prevElement 
     * @param {*} nextElement 
     */
    this.linkElement = function(prevElement, nextElement){
        if(!prevElement || !nextElement) return;
        
        prevElement.__nextSibling = nextElement;
        nextElement.__prevSibling = prevElement;
    }
}
